package gotnames.dm;

import gotnames.Utils;

import java.util.Collection;
import java.util.Collections;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import com.medallia.tiny.CollUtils;

/**
 * Helper class for executing a {@link Query} in simpler and more type-safe
 * ways. Use {@link #begin(PersistenceManager, Class)} to start a query.
 */
public class QueryBuilder<X> {
	
	private final Query query;
	
	private QueryBuilder(PersistenceManager pm, Class<X> entity) {
		this.query = pm.newQuery(entity);
	}
	
	/** @return all objects with the given primary keys; the field must be named 'key' */
	public Collection<X> getAllByKey(Collection<? extends Object> keys) {
		return getAllByKey("key", keys);
	}
	/** Same as {@link #getAllByKey(Collection)}, but the name of the primary key field is given */
	public Collection<X> getAllByKey(String field, Collection<? extends Object> keys) {
		if (keys.isEmpty())
			return Collections.emptySet();
		
		query.setFilter(String.format(":keys.contains(%s)", field));
		return Utils.cast(query.execute(keys));
	}
	
	/** @return the object with the given primary key or null if not present; throws an exception if more than one is found */
	public X getSingleByKey(Object key) {
		return CollUtils.getOneOrNull(getAllByKey(Collections.singleton(key)));
	}
	
	/** @return the object where the given field has the given value or null if not present; throws an exception if more than one is found */
	public X getSingleByField(String field, String value) {
		query.setFilter(field + " == fieldParam");
		query.declareParameters("String fieldParam");
		return CollUtils.getOneOrNull(Utils.<Collection<X>>cast(query.execute(value)));
	}

	/** Start the query */
	public static <X> QueryBuilder<X> begin(PersistenceManager pm, Class<X> entity) {
		return new QueryBuilder<X>(pm, entity);
	}

}
